import mediapipe as mp
import cv2
import numpy as np


class Hands:
    def __init__(self):
        self.mp_hands = mp.solutions.hands.Hands()
        self.frame = None
        self.landmarks_list = []
        self.handedness_list = []
        self.bent_counts = {"Left": 5, "Right": 5}
        print("Hands object created")

    def draw_style(self, frame):
        try:
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            result = self.mp_hands.process(frame_rgb)
            multi_hand_landmarks = result.multi_hand_landmarks
            multi_handedness = result.multi_handedness

            if multi_hand_landmarks and multi_handedness:
                self.landmarks_list = []
                self.handedness_list = []
                for hand_landmarks, handedness in zip(multi_hand_landmarks, multi_handedness):
                    conns = mp.solutions.hands.HAND_CONNECTIONS
                    hands_style = mp.solutions.drawing_utils.DrawingSpec(color=(0, 0, 0), thickness=2)
                    conns_style = mp.solutions.drawing_utils.DrawingSpec(color=(0, 0, 0), thickness=1)
                    mp.solutions.drawing_utils.draw_landmarks(
                        image=frame,
                        landmark_list=hand_landmarks,
                        connections=conns,
                        landmark_drawing_spec=hands_style,
                        connection_drawing_spec=conns_style,
                    )
                    self.landmarks_list.append(hand_landmarks.landmark)
                    self.handedness_list.append(handedness.classification[0].label)
                return True
            else:
                print("没有获取手部信息")
                return False
        except Exception as e:
            print(f"绘制过程中出现的错误: {e}")
            return False

    def gesture_num(self):
        self.bent_counts = {"Left": 5, "Right": 5}
        top_point_num = [4, 8, 12, 16, 20]

        for landmarks, handedness in zip(self.landmarks_list, self.handedness_list):
            finger_status = np.zeros((12,), dtype=np.int8)
            for index, num in enumerate(top_point_num):
                if index == 0:
                    continue
                top_p = self.index_convert_num(num)[1]
                mid_p = self.index_convert_num(num - 2)[1]
                top_p1 = self.index_convert_num(4)[0]
                mid_p1 = self.index_convert_num(2)[0]
                finger_status[index] = top_p < mid_p
                if handedness == "Right":
                    finger_status[index + 1] = top_p1 > mid_p1
                else:  # Left hand
                        finger_status[index + 1] = top_p1 < mid_p1
                # 未弯曲

                # 弯曲
                # if top_p > mid_p:
                #     print(index, top_p, mid_p, "弯曲")
            cnt = np.sum(finger_status)
            print(cnt)

            bent_count = 5
            for num in top_point_num:
                if num == 4:
                    top_p = self.index_convent_num(num, landmarks)[0]
                    mid_p = self.index_convent_num(num-2, landmarks)[0]
                    if handedness == "Right":
                        if mid_p < top_p:
                            bent_count -= 1
                    else:  # Left hand
                        if mid_p > top_p:
                            bent_count -= 1
                else:
                    top_p = self.index_convent_num(num, landmarks)[1]
                    mid_p = self.index_convent_num(num - 2, landmarks)[1]
                    if mid_p < top_p:
                        bent_count -= 1
            self.bent_counts[handedness] = bent_count
            print(bent_count)

    def index_convent_num(self, index):
        frame_h, frame_w, _ = self.frame.shape

        lm = self.landmarks[index]
        x = round(lm.x * frame_w)
        y = round(lm.y * frame_h)
        return x, y


    def process(self, frame):
        self.frame = frame
        if self.draw_style(self.frame):
            self.gesture_num()
            cv2.putText(frame, f"Left hand bent fingers: {self.bent_counts['Left']}", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            cv2.putText(frame, f"Right hand bent fingers: {self.bent_counts['Right']}", (20, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)


if __name__ == '__main__':
    mp_hands = Hands()
    cap = cv2.VideoCapture(0)

    if not cap.isOpened():
        print("未打开摄像头")
        exit()

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            print("未获得画面")
            break

        try:
            mp_hands.process(frame)
            cv2.imshow('Hands Detection', frame)
        except Exception as e:
            print("关键点检测出现错误:", e)

        key = cv2.waitKey(60)
        if key == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()